home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / bios.c < prev    next >
C/C++ Source or Header  |  1994-02-11  |  23KB  |  980 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * BIOS replacement routines
  9.  */
  10.  
  11. #include "mint.h"
  12. #include "xbra.h"
  13.  
  14. #define UNDEF 0        /* should match definition in tty.c */
  15.  
  16. /* some key definitions */
  17. #define CTRLALT 0xc
  18. #define DEL 0x53    /* scan code of delete key */
  19. #define UNDO 0x61    /* scan code of undo key */
  20.  
  21. /* BIOS device definitions */
  22. #define CONSDEV 2
  23. #define AUXDEV 1
  24. #define PRNDEV 0
  25.  
  26. /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
  27. #define MAX_BHANDLE    4
  28.  
  29. /* BIOS redirection maps */
  30. const short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
  31. const short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
  32.  
  33. /* tty structures for the BIOS devices -- see biosfs.c */
  34. extern struct tty con_tty, aux_tty, midi_tty;
  35.  
  36. extern int tosvers;    /* from main.c */
  37.  
  38. char *kbshft;        /* set in main.c */
  39.  
  40. short console_in;    /* wait condition for console input */
  41.  
  42. /* some BIOS vectors; note that the routines at these vectors may do nasty
  43.  * things to registers!
  44.  */
  45.  
  46. #define RWABS *((long *)0x476L)
  47. #define MEDIACH *((long *)0x47eL)
  48. #define GETBPB *((long *)0x472L)
  49.  
  50.  
  51. #if 1
  52. /* these are supposed to be tables holding the addresses of the
  53.  * first 8 BconXXX functions, but in fact only the first 5 are
  54.  * placed here (and device 5 only has Bconout implemented; 
  55.  * we don't use that device (raw console) anyway).
  56.  */
  57.  
  58. #define xconstat ((long *)0x51eL)
  59. #define xconin     ((long *)0x53eL)
  60. #define xcostat ((long *)0x55eL)
  61. #define xconout    ((long *)0x57eL)
  62.  
  63. #define BCOSTAT(dev) \
  64.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  65.        (int)callout1(xcostat[dev], dev) : Bcostat(dev))
  66. #define BCONOUT(dev, c) \
  67.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  68.        callout2(xconout[dev], dev, c) : Bconout(dev, c))
  69. #define BCONSTAT(dev) \
  70.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  71.        (int)callout1(xconstat[dev], dev) : Bconstat(dev))
  72. #define BCONIN(dev) \
  73.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  74.        callout1(xconin[dev], dev) : Bconin(dev))
  75. #else
  76. #define BCOSTAT(dev) Bcostat(dev)
  77. #define BCONOUT(dev,c) Bconout(dev,c)
  78. #define BCONSTAT(dev) Bconstat(dev)
  79. #define BCONIN(dev) Bconin(dev)
  80. #endif
  81.  
  82. /* variables for monitoring the keyboard */
  83. IOREC_T    *keyrec;        /* keyboard i/o record pointer */
  84. short    kintr = 0;        /* keyboard interrupt pending (see intr.s) */
  85.  
  86. /* Getmpb is not allowed under MiNT */
  87.  
  88. long ARGS_ON_STACK
  89. getmpb(ptr)
  90.     void *ptr;
  91. {
  92.     UNUSED(ptr);
  93.  
  94.     DEBUG(("failed call to Getmpb"));
  95.     return -1;
  96. }
  97.  
  98.  
  99. /*
  100.  * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
  101.  * to get the physical devices, go through u:\dev\
  102.  *
  103.  * A note on translation: all of the bco[n]XXX functions have a "u"
  104.  * variant that is actually what the user calls. For example,
  105.  * ubconstat is the function that gets control after the user does
  106.  * a Bconstat. It figures out what device or file handle is
  107.  * appropriate. Typically, it will be a biosfs file handle; a
  108.  * request is sent to biosfs, and biosfs in turn figures out
  109.  * the "real" device and calls bconstat.
  110.  */
  111.  
  112. /*
  113.  * WARNING: syscall.spp assumes that ubconstat never blocks.
  114.  */
  115. long ARGS_ON_STACK
  116. ubconstat(dev)
  117. int dev;
  118. {
  119.     if (dev < MAX_BHANDLE) {
  120.         FILEPTR *f = curproc->handle[binput[dev]];
  121.         return file_instat(f) ? -1 : 0;
  122.     }
  123.     else
  124.         return bconstat(dev);
  125. }
  126.  
  127. long
  128. bconstat(dev)
  129. int dev;
  130. {
  131.     if (dev == CONSDEV) {
  132.         if (checkkeys()) return 0;
  133.         return (keyrec->head != keyrec->tail) ? -1 : 0;
  134.     }
  135.     if (dev == AUXDEV && has_bconmap)
  136.         dev = curproc->bconmap;
  137.  
  138.     return BCONSTAT(dev);
  139. }
  140.  
  141. /* bconin: input a character */
  142. /*
  143.  * WARNING: syscall.spp assumes that ubconin never
  144.  * blocks if ubconstat returns non-zero.
  145.  */
  146. long ARGS_ON_STACK
  147. ubconin(dev)
  148. int dev;
  149. {
  150.     if (dev < MAX_BHANDLE) {
  151.         FILEPTR *f = curproc->handle[binput[dev]];
  152.         return file_getchar(f, RAW);
  153.     }
  154.     else
  155.         return bconin(dev);
  156. }
  157.  
  158. long
  159. bconin(dev)
  160. int dev;
  161. {
  162.     IOREC_T *k;
  163.     long r;
  164.     short h;
  165.  
  166.     if (dev == CONSDEV) {
  167.         k = keyrec;
  168. again:
  169.         while (k->tail == k->head) {
  170.             sleep(IO_Q, (long)&console_in);
  171.         }
  172.  
  173.         if (checkkeys()) goto again;
  174.  
  175.         h = k->head + 4;
  176.         if (h >= k->buflen)
  177.             h = 0;
  178.         r = *((long *)(k->bufaddr + h));
  179.         k->head = h;
  180.         return r;
  181.     }
  182.     else {
  183.         if (dev == AUXDEV && has_bconmap)
  184.             dev = curproc->bconmap;
  185.  
  186.         if (dev > 0) {
  187.             unsigned long tick;
  188.  
  189.             tick = *((unsigned long *)0x4baL);
  190.             while (!BCONSTAT(dev)) {
  191. /* make blocking (for longer) reads eat less CPU...
  192.  * if yield()ed > 2 seconds and still no data continue with nap
  193.  */
  194.             if ((*((unsigned long *)0x4baL) - tick) > 400)
  195.                 nap(60);
  196.             else
  197.                 yield();
  198.             }
  199.         }
  200.     }
  201.  
  202.     r = BCONIN(dev);
  203.  
  204.     return r;
  205. }
  206.  
  207. /* bconout: output a character.
  208.  * returns 0 for failure, nonzero for success
  209.  */
  210.  
  211. long ARGS_ON_STACK
  212. ubconout(dev, c)
  213. int dev, c;
  214. {
  215.     FILEPTR *f;
  216.     char outp;
  217.  
  218.     if (dev < MAX_BHANDLE) {
  219.         f = curproc->handle[boutput[dev]];
  220.         if (!f) return 0;
  221.         if (is_terminal(f)) {
  222.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  223.         }
  224.         outp = c;
  225.         return (*f->dev->write)(f, &outp, 1L);
  226.     }
  227.     else if (dev == 5) {
  228.         c &= 0x00ff;
  229.         f = curproc->handle[-1];
  230.         if (!f) return 0;
  231.         if (is_terminal(f)) {
  232.             if (c < ' ') {
  233.             /* MW hack for quoted characters */
  234.                 tty_putchar(f, (long)'\033', RAW);
  235.                 tty_putchar(f, (long)'Q', RAW);
  236.             }
  237.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  238.         }
  239.     /* note: we're assuming sizeof(int) == 2 here! */
  240.         outp = c;
  241.         return (*f->dev->write)(f, &outp, 1L);
  242.     } else
  243.         return bconout(dev, c);
  244. }
  245.  
  246. long
  247. bconout(dev, c)
  248. int dev,c;
  249. {
  250.     int statdev;
  251.     long endtime;
  252. #define curtime *((unsigned long *)0x4baL)
  253.  
  254.     if (dev == AUXDEV && has_bconmap) {
  255.         dev = curproc->bconmap;
  256.     }
  257.  
  258. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  259.     if (dev == 3) {        /* MIDI */
  260.         statdev = 4;
  261.     } else if (dev == 4) {
  262.         statdev = 3;
  263.     } else {
  264.         statdev = dev;
  265.     }
  266.  
  267. /* provide a 10 second time out for the printer */
  268.     if (!BCOSTAT(statdev)) {
  269.         if (dev != PRNDEV) {
  270.             do {
  271.     /* BUG: Speedo GDOS isn't re-entrant; so printer output to the
  272.      * serial port could cause problems
  273.      */
  274.                 yield();
  275.             } while (!BCOSTAT(statdev));
  276.         } else {
  277.             endtime = curtime + 10*200L;
  278.             do {
  279. #if 0
  280.     /* Speedo GDOS isn't re-entrant, so we can't give up CPU
  281.      * time here :-(
  282.      */
  283.                 yield();
  284. #endif
  285.             } while (!BCOSTAT(statdev) && curtime < endtime);
  286.             if ( curtime >= endtime) return 0;
  287.         }
  288.     }
  289.  
  290. /* special case: many text accelerators return a bad value from
  291.  * Bconout, so we ignore the returned value for the console
  292.  * Sigh. serptch2 and hsmodem1 also screw this up, so for now let's
  293.  * only count on it being correct for the printer.
  294.  */
  295.     if (dev == PRNDEV) {
  296. /* NOTE: if your compiler complains about the next line, then Bconout is
  297.  * improperly declared in your osbind.h header file. it should be returning
  298.  * a long value; some libraries incorrectly have Bconout returning void
  299.  * (or cast the returned value to void)
  300.  */
  301.         return BCONOUT(dev,c);
  302.     } else {
  303.         (void)BCONOUT(dev, c);
  304.         return 1;
  305.     }
  306. }
  307.  
  308. /* rwabs: various disk stuff */
  309.  
  310. long ARGS_ON_STACK
  311. rwabs(rwflag, buffer, number, recno, dev, lrecno)
  312. int rwflag, number, recno, dev;
  313. void *buffer;
  314. long lrecno;
  315. {
  316.     long r;
  317.     extern PROC *dlockproc[];    /* in dosdir.c */
  318.     extern int aliasdrv[];        /* in filesys.c */
  319.  
  320.     if (dev >= 0 && dev < NUM_DRIVES) {
  321.         if (aliasdrv[dev]) {
  322.             dev = aliasdrv[dev] - 1;
  323.         }
  324.         if (dlockproc[dev] && dlockproc[dev] != curproc) {
  325.             DEBUG(("Rwabs: device %c is locked", dev+'A'));
  326.             return ELOCKED;
  327.         }
  328.     }
  329.  
  330. #if 1
  331. /* only the superuser can make Rwabs calls directly */
  332.  
  333.     if (curproc->in_dos || (curproc->euid == 0))
  334.     /* Note that some (most?) Rwabs device drivers don't bother saving
  335.      * registers, whereas our compiler expects politeness. So we go
  336.      * via callout(), which will save registers for us.
  337.      */
  338.         r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
  339.     else {
  340.         DEBUG(("Rwabs by non privileged process!"));
  341.         r = EACCDN;
  342.     }
  343. #else
  344.     r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
  345. #endif
  346.     return r;
  347. }
  348.  
  349. /* setexc: set exception vector */
  350.  
  351. long ARGS_ON_STACK
  352. setexc(number, vector)
  353. int number;
  354. long vector;
  355. {
  356.     long *place;
  357.     long old;
  358.     extern long save_dos, save_bios, save_xbios;    /* in main.c */
  359.     extern int no_mem_prot;                /* in main.c */
  360.  
  361.     place = (long *)(((long)number) << 2);
  362.     if (number == 0x21)                /* trap_1 */
  363.         old = save_dos;
  364.     else if (number == 0x2d)            /* trap_13 */
  365.         old = save_bios;
  366.     else if (number == 0x2e)            /* trap_14 */
  367.         old = save_xbios;
  368.     else if (number == 0x101)
  369.         old = (long)curproc->criticerr;        /* critical error vector */
  370.     else if (number == 0x102)
  371.         old = curproc->ctxt[SYSCALL].term_vec;    /* GEMDOS term vector */
  372.     else
  373.         old = *place;
  374.  
  375.     if (vector > 0) {
  376.     /* validate vector; this will cause a bus error if mem
  377.      * protection is on and the current process doesn't have
  378.      * access to the memory
  379.      */
  380.         if (*((long *)vector) == 0xDEADBEEFL)
  381.             return old;
  382.  
  383.         if (number == 0x21)
  384.             save_dos = vector;
  385.         else if (number == 0x2d)
  386.             save_bios = vector;
  387.         else if (number == 0x2e)
  388.             save_xbios = vector;
  389.         else if (number == 0x102)
  390.             curproc->ctxt[SYSCALL].term_vec = vector;
  391.         else if (number == 0x101) {
  392.             long mintcerr;
  393.  
  394.         /*
  395.          * problem: lots of TSR's look for the Setexc(0x101,...)
  396.           * that the AES does at startup time; so we have
  397.          * to pass it along.
  398.          */
  399.             mintcerr = (long) Setexc(0x101, (void *)vector);
  400.             curproc->criticerr = (long ARGS_ON_STACK (*) P_((long))) *place;
  401.             *place = mintcerr;
  402.         }
  403.         else {
  404.             if (!no_mem_prot) {
  405.             /*
  406.              * if memory protection is on, the vector should be
  407.              * pointing at supervisor or global memory
  408.              */
  409.                 MEMREGION *r;
  410.  
  411.                 r = addr2region(vector);
  412.                 if (r && get_prot_mode(r) == PROT_P) {
  413.                 DEBUG(("Changing protection to Supervisor because of Setexc"));
  414.                 mark_region(r, PROT_S);
  415.                 }
  416.             }
  417.         /* We would do just *place = vector except that
  418.          * someone else might be intercepting Setexc looking
  419.          * for something in particular...
  420.          */
  421.             old = (long) Setexc(number, (void *)vector);
  422.         }
  423.     }
  424.  
  425.     TRACE(("Setexc %d, %lx -> %lx", number, vector, old));
  426.     return old;
  427. }
  428.  
  429. /* tickcal: return milliseconds per system clock tick */
  430.  
  431. long ARGS_ON_STACK
  432. tickcal()
  433. {
  434.     return (long) (*( (unsigned *) 0x0442L ));
  435. }
  436.  
  437. /* getbpb: get BIOS parameter block */
  438.  
  439. long ARGS_ON_STACK
  440. getbpb(dev)
  441. int dev;
  442. {
  443.     long r;
  444.  
  445. /* we can't trust the Getbpb routine to accurately save all registers,
  446.  * so we do it ourselves
  447.  */
  448.     r = callout1(GETBPB, dev);
  449. /* 
  450.  * There is a bug in the  TOS  disk handling routines (well several actually).
  451.  * If the directory size of Getbpb() is returned as zero then the drive 'dies'
  452.  * and wont read any new disks even with the 'ESC' enforced disk change . This
  453.  * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
  454.  * changes the dir size to '1' if it is zero . It may make some non-TOS disks
  455.  * look a bit weird but that's better than killing the drive .
  456.  */
  457.     if (r) {
  458.         if ( ((short *)r)[3] == 0)    /* 0 directory size? */
  459.             ((short *)r)[3] = 1;
  460.     }
  461.     return r;
  462. }
  463.  
  464. /* bcostat: return output device status */
  465.  
  466. /* WARNING: syscall.spp assumes that ubcostat never
  467.  * blocks
  468.  */
  469. long ARGS_ON_STACK
  470. ubcostat(dev)
  471. int dev;
  472. {
  473.     FILEPTR *f;
  474.  
  475. /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
  476.     if (dev == 4) {        /* really the MIDI port */
  477.         f = curproc->handle[boutput[3]];
  478.         return file_outstat(f) ? -1 : 0;
  479.     }
  480.     if (dev == 3)
  481.         return BCOSTAT(dev);
  482.  
  483.     if (dev < MAX_BHANDLE) {
  484.         f = curproc->handle[boutput[dev]];
  485.         return file_outstat(f) ? -1 : 0;
  486.     } else
  487.         return bcostat(dev);
  488. }
  489.  
  490. long
  491. bcostat(dev)
  492. int dev;
  493. {
  494.  
  495.     if (dev == CONSDEV) {
  496.         return -1;
  497.     }
  498.     else if (dev == AUXDEV && has_bconmap) {
  499.         dev = curproc->bconmap;
  500.     }
  501. /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
  502.  * correctly
  503.  */
  504.     else if (dev == 3) dev = 4;
  505.     else if (dev == 4) dev = 3;
  506.  
  507.     return BCOSTAT(dev);
  508. }
  509.  
  510. /* mediach: check for media change */
  511.  
  512. long ARGS_ON_STACK
  513. mediach(dev)
  514. int dev;
  515. {
  516.     long r;
  517.  
  518.     r = callout1(MEDIACH, dev);
  519.     return r;
  520. }
  521.  
  522. /* drvmap: return drives connected to system */
  523.  
  524. long ARGS_ON_STACK
  525. drvmap()
  526. {
  527.     return *( (long *)0x4c2L );
  528. }
  529.  
  530. /* kbshift: return (and possibly change) keyboard shift key status */
  531. /* WARNING: syscall.spp assumes that kbshift never blocks, and never
  532.  * calls any underlying TOS functions
  533.  */
  534. long ARGS_ON_STACK
  535. kbshift(mode)
  536. int mode;
  537. {
  538.     int oldshft;
  539.  
  540.     oldshft = *((unsigned char *)kbshft);
  541.     if (mode >= 0)
  542.         *kbshft = mode;
  543.     return oldshft;
  544. }
  545.  
  546.  
  547. /* special Bconout buffering code:
  548.  * Because system call overhead is so high, programs that do output
  549.  * with Bconout suffer in performance. To compensate for this,
  550.  * Bconout is special-cased in syscall.s, and if possible characters
  551.  * are placed in the 256 byte bconbuf buffer. This buffer is flushed
  552.  * when any system call other than Bconout happens, or when a context
  553.  * switch occurs.
  554.  */
  555.  
  556. short bconbsiz;            /* number of characters in buffer */
  557. unsigned char bconbuf[256];    /* buffer contents */
  558. short bconbdev;            /* BIOS device for which the buffer is valid */
  559.                 /* (-1 means no buffering is active) */
  560.  
  561. /*
  562.  * flush pending BIOS output. Return 0 if some bytes were not successfully
  563.  * written, non-zero otherwise (just like bconout)
  564.  */
  565.  
  566. long ARGS_ON_STACK
  567. bflush()        /* flush bios output */
  568. {
  569.     long ret, bsiz;
  570.     unsigned char *s;
  571.     FILEPTR *f;
  572.     short dev;
  573.     short statdev;
  574.     long lbconbuf[256];
  575.  
  576.     if ((dev = bconbdev) < 0) return 0;
  577.  
  578. /*
  579.  * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
  580.  * This is necessary because if two or more programs try to do
  581.  * buffered BIOS output at the same time, they can get seriously
  582.  * mixed up. We unlock by setting bconbdev to 0.
  583.  *
  584.  * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
  585.  * order to see if we need to do a bflush; if one is already in
  586.  * progress, it's pointless to do this, so we save a bit of
  587.  * time by setting bconbsiz to 0 here.
  588.  */
  589.     bconbdev = -1;
  590.     bsiz = bconbsiz;
  591.     if (bsiz == 0) return 0;
  592.     bconbsiz = 0;
  593.  
  594. /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
  595.     if (dev < MAX_BHANDLE || dev == 5) {
  596.         if (dev == 5)
  597.             f = curproc->handle[-1];
  598.         else
  599.             f = curproc->handle[boutput[dev]];
  600.  
  601.         if (!f) {
  602.             bconbdev = 0;
  603.             return 0;
  604.         }
  605.         if (is_terminal(f)) {
  606.             s = bconbuf;
  607.             if (dev == 5) {
  608.                 while (bsiz-- > 0) {
  609.                 if (*s < ' ') {
  610.             /* use ESC-Q to quote control character */
  611.                     (void)tty_putchar(f, (long)'\033',
  612.                                 RAW);
  613.                     (void)tty_putchar(f, (long)'Q',
  614.                                 RAW);
  615.                 }
  616.                 (void) tty_putchar(f, (long)*s++, RAW);
  617.                 }
  618.             } else {
  619. #if 1
  620.                 long *where, nbytes;
  621.  
  622. /* the tty_putchar should set up terminal modes correctly */
  623.                 (void) tty_putchar(f, (long)*s++, RAW);
  624.                 where = lbconbuf;
  625.                 nbytes = 0;
  626.                 while (--bsiz > 0) {
  627.                 *where++ = *s++; nbytes+=4;
  628.                 }
  629.                 if (nbytes)
  630.                 (*f->dev->write)(f, (char *)lbconbuf, nbytes);
  631. #else
  632.                 while (bsiz-- > 0) {
  633.                 (void) tty_putchar(f, (long)*s++, RAW);
  634.                 }
  635. #endif
  636.             }
  637.             ret = -1;
  638.         } else {
  639.             ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
  640.         }
  641.         bconbdev = 0;
  642.         return ret;
  643.     }
  644.  
  645. /* Otherwise, we have a real BIOS device */
  646.  
  647.     if (dev == AUXDEV && has_bconmap) {
  648.         dev = curproc->bconmap;
  649.         statdev = dev;
  650.     }
  651. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  652.     else if (dev == 3) {        /* MIDI */
  653.         statdev = 4;
  654.     } else if (dev == 4) {
  655.         statdev = 3;
  656.     } else
  657.         statdev = dev;
  658.         
  659.     s = bconbuf;
  660.     while (bsiz-- > 0) {
  661.         while (!BCOSTAT(statdev)) yield();
  662.         (void)BCONOUT(dev,*s);
  663.         s++;
  664.     }
  665.     bconbdev = 0;
  666.     return 1L;
  667. }
  668.  
  669. /* initialize bios table */
  670.  
  671. #define BIOS_MAX 0x20
  672.  
  673. Func bios_tab[BIOS_MAX] = {
  674.     getmpb,
  675.     ubconstat,
  676.     ubconin,
  677.     ubconout,
  678.  
  679.     rwabs,
  680.     setexc,
  681.     tickcal,
  682.     getbpb,
  683.  
  684.     ubcostat,
  685.     mediach,
  686.     drvmap,
  687.     kbshift,
  688.  
  689.     0, 0, 0, 0,
  690.     0, 0, 0, 0, 0, 0, 0, 0,
  691.     0, 0, 0, 0, 0, 0, 0, 0
  692. };
  693.  
  694. short bios_max = BIOS_MAX;
  695.  
  696. /*
  697.  * BIOS initialization routine: gets keyboard buffer pointers, for the
  698.  * interrupt routine below
  699.  */
  700.  
  701. void
  702. init_bios()
  703. {
  704.     keyrec = (IOREC_T *)Iorec(1);
  705. }
  706.  
  707. /*
  708.  * do_bconin: try to do a bconin function quickly, without
  709.  * blocking. If we can't do it without blocking, we return
  710.  * 0x0123dead and the calling trap #13 code falls through
  711.  * to the normal bconin stuff. We can't block here because
  712.  * the trap #13 code hasn't yet saved registers or other
  713.  * context bits, so sleep() wouldn't work properly.
  714.  */
  715.  
  716. #define WOULDBLOCK 0x0123deadL
  717.  
  718. /* WARNING: syscall.spp assumes that do_bconin never blocks */
  719.  
  720. long ARGS_ON_STACK
  721. do_bconin(dev)
  722.     int dev;
  723. {
  724.     FILEPTR *f;
  725.     long r;
  726.     unsigned char c;
  727.  
  728.     if (dev < MAX_BHANDLE) {
  729.         f = curproc->handle[binput[dev]];
  730.         if (!f) return 0;
  731.         r = 0;
  732.         (void)(*f->dev->ioctl)(f, FIONREAD, &r);
  733.         if (!r) return WOULDBLOCK;    /* data not ready */
  734.         if (is_terminal(f))
  735.             r = tty_getchar(f, RAW);
  736.         else {
  737.             r = (*f->dev->read)(f, (char *)&c, 1L);
  738.             r = (r == 1) ? c : MiNTEOF;
  739.         }
  740.     } else {
  741.         if (!bconstat(dev))
  742.             r = WOULDBLOCK;
  743.         else
  744.             r = bconin(dev);
  745.     }
  746.     return r;
  747. }
  748.  
  749. /*
  750.  * routine for checking keyboard (called by sleep() on any context
  751.  * switch where a keyboard event occured). returns 1 if a special
  752.  * control character was eaten, 0 if not
  753.  */
  754.  
  755. int
  756. checkkeys()
  757. {
  758.     char scan, ch;
  759.     short shift;
  760.     int sig, ret;
  761.     struct tty *tty = &con_tty;
  762.     extern char mshift;        /* for mouse -- see biosfs.c */
  763.     static short oldktail = 0;
  764.  
  765.     ret = 0;
  766.     mshift = kbshift(-1);
  767.     while (oldktail != keyrec->tail) {
  768.  
  769. /* BUG: we really should check the shift status _at the time the key was
  770.  * pressed_, not now!
  771.  */
  772.         sig = 0;
  773.         shift = mshift;
  774.         oldktail += 4;
  775.         if (oldktail >= keyrec->buflen)
  776.             oldktail = 0;
  777.  
  778.         scan = (keyrec->bufaddr + oldktail)[1];
  779. /* function key?? */
  780.         if ( (scan >= 0x3b && scan <= 0x44) ||
  781.              (scan >= 0x54 && scan <= 0x5d) ||
  782.              scan == DEL || scan == UNDO) {
  783.             if ( (shift & CTRLALT) == CTRLALT ) {
  784.                 oldktail = keyrec->head = keyrec->tail;
  785.                 do_func_key(scan);
  786.                 /* do_func_key may have read some keys */
  787.                 oldktail = keyrec->head;
  788.                 mshift = kbshift (-1);
  789.                 ret = 1;
  790.                 continue;
  791.             }
  792.         }
  793.  
  794. /* check for special control keys, etc. */
  795. /* BUG: this doesn't exactly match TOS' behavior, particularly for
  796.  * ^S/^Q
  797.  */
  798.         if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
  799.             ch = (keyrec->bufaddr + keyrec->tail)[3];
  800.             if (ch == UNDEF)
  801.                 ;    /* do nothing */
  802.             else if (ch == tty->tc.t_intrc)
  803.                 sig = SIGINT;
  804.             else if (ch == tty->tc.t_quitc)
  805.                 sig = SIGQUIT;
  806.             else if (ch == tty->ltc.t_suspc)
  807.                 sig = SIGTSTP;
  808.             else if (ch == tty->tc.t_stopc) {
  809.                 tty->state |= TS_HOLD;
  810.                 ret = 1;
  811.                 keyrec->head = oldktail;
  812.                 continue;
  813.             }
  814.             else if (ch == tty->tc.t_startc) {
  815.                 tty->state &= ~TS_HOLD;
  816.                 ret = 1;
  817.                 keyrec->head = oldktail;
  818.                 continue;
  819.             }
  820.             if (sig) {
  821.                 tty->state &= ~TS_HOLD;
  822.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  823.                     oldktail = keyrec->head = keyrec->tail;
  824.                 killgroup(tty->pgrp, sig);
  825.                 ret = 1;
  826.             }
  827.             else if (tty->state & TS_HOLD) {
  828.                 keyrec->head = oldktail;
  829.                 ret = 1;
  830.             }
  831.         }
  832.  
  833.     }
  834.  
  835.     if (keyrec->head != keyrec->tail) {
  836.     /* wake up any processes waiting in bconin() */
  837.         wake(IO_Q, (long)&console_in);
  838.     /* wake anyone that did a select() on the keyboard */
  839.         if (tty->rsel)
  840.             wakeselect(tty->rsel);
  841.     }
  842.  
  843.     return ret;
  844. }
  845.  
  846.  
  847. /*
  848.  * special vector stuff: we try to save as many vectors as possible,
  849.  * just in case we need to restore them later
  850.  *
  851.  * BUG: this really should be integrated with the init_intr routine
  852.  * in main.c
  853.  */
  854.  
  855. #define A(x) ((long *)(long)(x))
  856. #define L(x) (long)(x)
  857.  
  858. struct vectab {
  859.     long *addr;
  860.     long def_value;
  861. } VEC[] = {
  862. {A(0x28), 0},    /* Line A */
  863. {A(0x2c), 0},    /* Line F */
  864. {A(0x60), 0},    /* spurious interrupt */
  865. {A(0x64), 0},      /* level 1 interrupt */
  866. {A(0x68), 0},    /* level 2 interrupt */
  867. {A(0x6c), 0},    /* level 3 interrupt */
  868. {A(0x70), 0},    /* level 4 interrupt */
  869. {A(0x74), 0},    /* level 5 interrupt */
  870. {A(0x78), 0},    /* level 6 interrupt */
  871. {A(0x7c), 0},    /* level 7 interrupt */
  872. {A(0x100), 0},    /* various MFP interrupts */
  873. {A(0x104), 0},
  874. {A(0x108), 0},
  875. {A(0x10c), 0},
  876. {A(0x110), 0},
  877. {A(0x114), 0},
  878. {A(0x118), 0},
  879. {A(0x11c), 0},
  880. {A(0x120), 0},
  881. {A(0x124), 0},
  882. {A(0x128), 0},
  883. {A(0x12c), 0},
  884. {A(0x130), 0},
  885. {A(0x134), 0},
  886. {A(0x138), 0},
  887. {A(0x13c), 0},
  888. {A(0x400), 0},    /* etv_timer */
  889. {A(0x4f6), 0},  /* shell_p */
  890.  
  891. {A(0), 0}    /* special tag indicating end of list */
  892. };
  893.  
  894. void
  895. init_vectors() 
  896. {
  897.     struct vectab *v;
  898.  
  899.     for (v = VEC; v->addr; v++) {
  900.         v->def_value = *(v->addr);
  901.     } 
  902. }
  903.  
  904. #if 0    /* bad code */
  905.  
  906. /* unhook a vector; if possible, do this with XBRA, but
  907.  * if that isn't possible force the vector to have the
  908.  * same value it had when MiNT started
  909.  */
  910.  
  911. static void
  912. unhook(v, where)
  913.     struct vectab *v;
  914.     long where;
  915. {
  916.     xbra_vec *xbra;
  917.     long newval;
  918.     int cookie;
  919.  
  920. /* to check for XBRA, we need access to the memory where the
  921.  * vector is
  922.  */
  923.     cookie = prot_temp(where - 12, 16L, -1);
  924.  
  925.     if (cookie == 0)
  926.         newval = v->def_value;
  927.     else {
  928.         xbra = (xbra_vec *)(where - 12);
  929.         if (xbra->xbra_magic == XBRA_MAGIC) {
  930.             newval = (long)xbra->next;
  931.         } else {
  932.             newval = v->def_value;
  933.         }
  934.     }
  935.     *(v->addr) = newval;
  936.  
  937.     (void)prot_temp(where - 12, 16L, cookie);
  938. }
  939. #endif
  940.  
  941. /*
  942.  * unlink_vectors(start, end): any of the "normal" system vectors
  943.  * pointing into a freed memory region must be reset to their
  944.  * default values, or else we'll get a memory protection violation
  945.  * next time the vector gets called
  946.  */
  947.  
  948. void
  949. unlink_vectors(start, end)
  950.     long start, end;
  951. {
  952. #if 0    /* this code is hosed somewhere */
  953.  
  954.     struct vectab *v;
  955.     long where, *p;
  956.     int i;
  957.  
  958. /* first, unhook any VBL handlers */
  959.     i = *((short *)0x454L);    /* i = nvbls */
  960.     p = *((long **)0x456L);    /* p = _vblqueue */
  961.     while (i-- > 0) {
  962.         where = *p;
  963.         if (where >= start && where < end)
  964.             *p = 0;
  965.         p++;
  966.     }
  967.  
  968. /* next, unhook various random vectors */
  969.     for (v = VEC; v->addr; v++) {
  970.         where = *(v->addr);
  971.         if (where >= start && where < end) {
  972.             unhook(v, where);
  973.         }
  974.     }
  975. #else
  976.     UNUSED(start); UNUSED(end);
  977. #endif
  978. }
  979.  
  980.